package com.ehotting.edsta.circuitDesign.service.impl;

import cn.hutool.core.lang.func.Func1;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.ehotting.edsta.circuitDesign.Constants;
import com.ehotting.edsta.circuitDesign.bean.*;
import com.ehotting.edsta.circuitDesign.bean.request.RequestCodeExecute;
import com.ehotting.edsta.circuitDesign.bean.request.RequestExecute;
import com.ehotting.edsta.circuitDesign.bean.request.RequestGetCircuitData;

import com.ehotting.edsta.circuitDesign.domain.*;
import com.ehotting.edsta.circuitDesign.enums.CircuitTypeEnum;
import com.ehotting.edsta.circuitDesign.enums.StorageTypeEnum;
import com.ehotting.edsta.circuitDesign.exception.LoggerTar;
import com.ehotting.edsta.circuitDesign.gen.SchemeEngine;
import com.ehotting.edsta.circuitDesign.service.*;

import com.ehotting.edsta.circuitDesign.uitls.CircuitThreadContext;
import com.ehotting.eaf.core.domain.R;
import com.ehotting.eaf.core.utils.OkHttpUtils;
import com.ehotting.eaf.redis.service.RedisService;
import com.ehotting.eaf.security.service.TokenService;
import com.ehotting.eaf.core.utils.StringUtils;
import com.ehotting.edsta.system.api.RemoteFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 电路生成Service业务层处理
 *
 * @author edsta
 * @date 2023-06-03
 */
@Service
@Slf4j
public class EsGenerateServiceImpl implements IEsGenerateService {


    @Value(value = "${circuitFilesIp}")
    private String circuitFilesIp;

    @Autowired
    private RedisService redisService;
    @Autowired
    IEsSceneParamService esSceneParamService;
    @Autowired
    private EsElementService esComponentService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private SchemeEngine schemeEngine;
    @Autowired
    private CircuitThreadContext circuitThreadContext;

    @Autowired
    private IEsCircuitCodeDataService esCircuitCodeDataService;

    @Resource
    private RemoteFileService remoteFileService;

    @Autowired
    private EsCircuitPcbService esCircuitPcbService;

    // ---------------- 1、生成电路（交互二）----------------

    /**
     *知识点：方案包
     *方案包包含：
     *1、最大最小价格（所有方案）
     *2、最大最小面积（所有方案）
     *3、最大最小功率（所有方案）
     *4、最大最小存储时间（所有方案）
     *5、存储器类型集合（所有方案）
     *6、处理器型号集合（所有方案）
     *7、方案列表schemeList、最大最小价格（所有方案）

     *方案SchemeBean包含：
     *1、价格、面积、功率、存储时间、存储器类型、处理器型号
     *2、方案中使用的电路模板circuit
     *3、方案中使用的电路模板circuit，这里用的是map存储，因为方案的电路模板结构有多层，所以用map，多层map嵌套；

     *一个方案会有多个电路类型
     *一个电路类型会有多个采集类型
     *一个采集类型会有多个电路模板

     *电路模板circuit结构：
     *Map<String, CircuitPackageBean> circuit = new HashMap<>(); key为电路类型，CircuitPackageBean为电路包

     *电路包CircuitPackageBean结构：
     *CircuitPackageBean 继承 HashMap<String,CircuitGroupBean>,key为采集类型，实际CircuitPackageBean是一个map；

     *电路包CircuitGroupBean结构：
     *CircuitGroupBean 继承 HashMap<Long, CircuitElementBean>,key为电路模板id，实际CircuitGroupBean结构是一个map；

     *电路模板CircuitElementBean结构：
     *电路模板信息、替换的元器件信息
     * @param param 参数
     * @return
     */
    @Override
    public R circuitGeneration(String param) {


        // 转换数据
        RequestExecute requestExecute = JSONObject.parseObject(param, RequestExecute.class);
        String mainProjectId = requestExecute.getMainProjectId();
        if(StringUtils.isEmpty(mainProjectId)){
            return R.fail("mainProjectId is null,Please start with the first step");
        }
        redisService.delete(Constant.Kill_Circuit_Generation_Thread+mainProjectId);
//        redisService.delete(Constant.Kill_Circuit_Generation_Thread+mainProjectId);
//        String s = redisService.get(Constant.Kill_Circuit_Generation_Thread + mainProjectId);
//        if(s != null && !Boolean.valueOf(s)) {
//            return R.fail(null,"匹配已停止:"+mainProjectId);
//        }
        RequestCodeExecute inputParam = new RequestCodeExecute(requestExecute);

        // 错误信息记录
        final String[] errMsg = {null};
        // 返回实体
        JSONObject jsonObject = new JSONObject();

        Thread thread = new Thread(() -> {
            try {
                circuitThreadContext.set(Constant.Kill_Circuit_Generation_Thread + mainProjectId);

                // 执行脚本，生成方案包SchemePackageBean
                SchemePackageBean schemePackage = schemeEngine.invoke(inputParam, mainProjectId);

                // 统计每个方案的价格、面积、功率、存储时间、处理器型号、存储类型；
                // 统计所有方案的最大最小价格、最大最小面积、最大最小功率、最大最小存储时间、处理器型号、存储类型；
                schemePackage = statistic(schemePackage, inputParam);

                // 生成id
                String id = UUID.randomUUID().toString();

                // 把数据存储到缓存
                redisService.setCacheObject(Constant.CIRCUIT_SCHEME_CACHE_KEY_PREFIX + id, schemePackage, 2L, TimeUnit.HOURS);

                // 返回id,在交互三中通过id查询数据
                jsonObject.put("id", id);
                jsonObject.put("total", schemePackage.getSchemeList().size());


                log.info("\n\n" +
                        "☆*: .｡. o(≧▽≦)o .｡.:*☆成功生成方案☆*: .｡. o(≧▽≦)o .｡.:*☆" +
                        "\nid:" + id + "\ttotal:" + schemePackage.getSchemeList().size() +
                        "\nmainProjectId:"+mainProjectId+
                        "\n\n");

            } catch (Exception e) {
                errMsg[0] = e.getMessage();
                e.printStackTrace();
            } finally {
                circuitThreadContext.remove();
            }
        });

        // 记录匹配工程开始标识到缓存
        long timeMillis = System.currentTimeMillis();
        redisService.setCacheObject(Constant.Kill_Circuit_Generation_Thread+mainProjectId, "true", 2L, TimeUnit.HOURS);
        thread.start();

        while (true) {
            try {
                Thread.sleep(500);
                if(!Boolean.valueOf(redisService.get(Constant.Kill_Circuit_Generation_Thread+mainProjectId))) {
                    return R.fail(jsonObject,"匹配已停止:"+mainProjectId);
                }
                if(jsonObject.get("total") != null){
//                    redisService.setCacheObject(Constant.Kill_Circuit_Generation_Thread+mainProjectId,"false");
                    return R.ok(jsonObject);
                }
                if( (System.currentTimeMillis()-timeMillis)/60000 > 3 ){
//                    redisService.setCacheObject(Constant.Kill_Circuit_Generation_Thread+mainProjectId,"false");
                    return R.fail(jsonObject,"请求已超时");
                }
                if(!StringUtils.isEmpty(errMsg[0])){
//                    redisService.setCacheObject(Constant.Kill_Circuit_Generation_Thread+mainProjectId,"false");
                    return R.fail(jsonObject,errMsg[0]);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return R.fail(e.getMessage());
            }
        }
    }



    // ---------------- 2、获取电路数据（交互三）----------------

    @Override
    public R getCircuitData(RequestGetCircuitData requestGetCircuitData,String token) {

        // 在缓存中查出生成的电路方案
        SchemePackageBean schemePackage = redisService.getCacheObject(Constant.CIRCUIT_SCHEME_CACHE_KEY_PREFIX + requestGetCircuitData.getId());

        List<SchemeBean> schemeList = schemePackage.getSchemeList();

        // 根据参数筛选出符合范围的数据
        FilterSetData filterSetData = requestGetCircuitData.getFilter();
        if (filterSetData != null) {
            schemeList = filterData(filterSetData, schemeList);
        }

        // 组装返回实体
        List<CircuitData> circuitDataList = packData(schemeList,token,requestGetCircuitData.getMainProjectId());
        if(!Boolean.valueOf(redisService.get(Constant.Kill_Circuit_Generation_Thread+requestGetCircuitData.getMainProjectId()))) {
            return R.fail(new JSONObject(),"匹配已停止:"+requestGetCircuitData.getMainProjectId());
        }
        int total = circuitDataList.size();
        int totalPage = circuitDataList.size() / requestGetCircuitData.getPageSize() + (circuitDataList.size() % requestGetCircuitData.getPageSize() == 0 ? 0 : 1);

        // 分页电路数据
        circuitDataList = pagingCircuit(requestGetCircuitData.getPage(), requestGetCircuitData.getPageSize(), circuitDataList);

        // 组装过滤条件参数
        FilterRangeData filterRangeData = new FilterRangeData();
        packFilterRangeData(filterRangeData, schemePackage);

        // 组装返回数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 200);
        jsonObject.put("msg", "ok");
        jsonObject.put("page", requestGetCircuitData.getPage());
        jsonObject.put("pageSize", requestGetCircuitData.getPageSize());
        jsonObject.put("total", total);
        jsonObject.put("totalPage", totalPage);
        jsonObject.put("filter", filterRangeData);
        jsonObject.put("lists", circuitDataList);

        log.info("交互三电路组装数据：{}",jsonObject);
        return R.ok(jsonObject);
    }


    // ---------------- 1-1生成电路（交互二）----------------
    // 统计每个方案的价格、面积、功率、存储时间、处理器型号、存储类型；
    // 统计所有方案的最大最小价格、最大最小面积、最大最小功率、最大最小存储时间、处理器型号、存储类型；
    public SchemePackageBean statistic(SchemePackageBean schemePackage, RequestCodeExecute inputParam) {
        List<SchemeBean> schemeList = schemePackage.getSchemeList();

        boolean download = true;

        // 所有方案的最大最小信息
        Double priceMax, priceMin, areaMax, areaMin, powerMax, powerMin, timeMax, timeMin;
        priceMax = priceMin = areaMax = areaMin = powerMax = powerMin = timeMax = timeMin = null;
        Set<String> packageTypeC = new HashSet<>(); // 存储器类型
        Set<String> packageModeC = new HashSet<>(); // 处理器型号

        // 多个方案
        aa :
        for (SchemeBean schemeBean : schemeList) {
            // 方案功率、面积、价格、存储时间
            double power, area, price, time;
            power = area = price = time = 0;
            // 方案存储器类型
            Set<String> typeC = new HashSet<>();
            // 方案处理器型号
            Set<String> modeC = new HashSet<>();

            // 一个方案的所有电路模板信息相加，统计
            // 一个方案有多个电路类型，这里循环多个电路类型
            for (String key : schemeBean.getCircuit().keySet()) {
                // 一个电路类型有多个采集类型，这里循环采集类型
                for (String key2 : schemeBean.getCircuit().get(key).keySet()) {
                    // 一个采集类型
                    CircuitGroupBean circuitGroupBean = schemeBean.getCircuit().get(key).get(key2);
                    // 获取这个采集类型的电路模板集合
                    List<CircuitElementBean> circuitElementBeanList = circuitGroupBean.getCircuitElementList();
                    // 一个采集类型有多个电路模板，这里循电路模板
                    for (CircuitElementBean circuitElementBean : circuitElementBeanList) {

                        for (int ic = 0; ic < circuitElementBean.getCount(); ic++) {

                            // 一个电路模块数据
                            // 通过bom表取得元器件的面积、价格、存储时间、处理器型号

                            // 判断Bom表格地址是否为空，不为空的话下载，解析成实体
                            if (!StringUtils.isBlank(circuitElementBean.getCircuit().getBomPath()) && download) {
                                List<CircuitData.BomData> bomDataList = analysisBom(circuitElementBean.getCircuit().getBomPath());
                                if (bomDataList == null) {
                                    schemeBean.setChoose(false);
                                    continue aa;
                                }
                                for (CircuitData.BomData bomData : bomDataList) {

                                    // 只要统计芯片的价格、功率、面积，位号是U开头的就是芯片
                                    // 判断如果是处理器的话，在bom表取出处理器型号Comment
                                    if (!StringUtils.isBlank(bomData.getDesignator()) && !StringUtils.isBlank(bomData.getComment())) {

                                        String aCase = bomData.getDesignator().subSequence(0, 1).toString().toUpperCase();
                                        if ("U".equals(aCase)) {
                                            // 元器件唯一编码，等于专家系统的元器件库编码code，bom表的Comment和专家系统的元器件库的code对应；
                                            // 数据库查找元器件的信息
                                            EsElement esElement = esComponentService.findOneByCode(bomData.getComment());

                                            if (esElement != null) {
                                                if (esElement.getPower() != null) { power = power + esElement.getPower();}
                                                if (esElement.getArea() != null) { area = area + esElement.getArea();}
                                                if (esElement.getPrice() != null) { price = price + esElement.getPrice();}
                                            }
                                        }
                                        // 获取处理器型号（M开头）
                                        if ("M".equals(bomData.getDesignator().subSequence(0, 1))
                                                && NumberUtils.isParsable(bomData.getDesignator().substring(1))) {
                                            modeC.add(bomData.getComment());
                                        }
                                    }
                                }
                            }

                            // 添加存储器类型，存储器类型通过电路模板数据可以取到
                            if (circuitElementBean.getCircuit().getStorageType() != null && circuitElementBean.getCircuit().getStorageType() != StorageTypeEnum.OTHER) {
                                typeC.add(circuitElementBean.getCircuit().getStorageType().getCode());
                            }

                        }

                    }
                }

                // 计算存储时间，判断是否存储类型，现在存储器和处理器合成处理器模块了
                Integer value = Integer.valueOf((String) inputParam.getData().get(Constants.Input_Param_Data_Analogue_Num));
                if (value > 0 && key.equals(CircuitTypeEnum.CONTROLLER.getCode())) {

                    Double maxSample = null;
                    Double maxSamplingBit = null;

                    // 取出最大采样率和最大分辨率
                    for (int i = 0; i < inputParam.getAnalogue().size(); i++) {
                        double sample = inputParam.getAnalogue().get(i).getSample();
                        double samplingBit = Double.parseDouble(inputParam.getAnalogue().get(i).getSamplingbit());

                        if (maxSample == null || sample > maxSample) {
                            maxSample = sample;
                        }
                        if (maxSamplingBit == null || samplingBit > maxSamplingBit) {
                            maxSamplingBit = samplingBit;
                        }
                    }

                    if (maxSample != null && maxSamplingBit != null) {
                        // 可能会有多个电路，所以多次计算，相加
                        for (String storageKey : schemeBean.getCircuit().get(key).keySet()) {
                            // 一个采集类型
                            CircuitGroupBean circuitGroupBean = schemeBean.getCircuit().get(key).get(storageKey);
                            // 获取这个采集类型的电路模板集合
                            List<CircuitElementBean> circuitElementBeanList = circuitGroupBean.getCircuitElementList();
                            // 一个采集类型有多个电路模板，这里循电路模板
                            for (CircuitElementBean circuitElementBean : circuitElementBeanList) {
                                for (int ic = 0; ic < circuitElementBean.getCount(); ic++) {
                                    // 判断是否存储类型，现在存储器和处理器合成处理器模块了
                                    // 判断存储容量是否大于0
                                    if (circuitElementBean.getCircuit().getStorageType() != null
                                            && circuitElementBean.getCircuit().getStorageCapacity() != null
                                            && circuitElementBean.getCircuit().getStorageCapacity() > 0) {

                                        // 数据库存的单位是mb,所以这里要转成B
                                        long storageCapacity = circuitElementBean.getCircuit().getStorageCapacity() * 1024 * 1024;
                                        // 存储时间计算：XX秒 = 存储容量（B）/(通道数*最大采样率*最大分辨率bit/8）；
                                        time = time + (storageCapacity / (inputParam.getAnalogue().size() * maxSample * maxSamplingBit / 8));
                                    }
                                }

                            }


                        }
                    }


                }

            }

            // 一个方案的信息
            schemeBean.setPower(power);
            schemeBean.setArea(area);
            schemeBean.setPrice(price);
            schemeBean.setTime(time);
            schemeBean.setTypeC(typeC);
            schemeBean.setModeC(modeC);


            // 统计所有方案的最大最小值
            // 赋予初始值
            powerMax = (powerMax == null) ? power : powerMax;
            powerMin = (powerMin == null) ? power : powerMin;
            areaMax = (areaMax == null) ? area : areaMax;
            areaMin = (areaMin == null) ? area : areaMin;
            priceMax = (priceMax == null) ? price : priceMax;
            priceMin = (priceMin == null) ? price : priceMin;
            timeMax = (timeMax == null) ? time : timeMax;
            timeMin = (timeMin == null) ? time : timeMin;

            // 选出最大最小值
            priceMax = (schemeBean.getPrice() != null && priceMax < schemeBean.getPrice()) ? schemeBean.getPrice() : priceMax;
            priceMin = (schemeBean.getPrice() != null && priceMin > schemeBean.getPrice()) ? schemeBean.getPrice() : priceMin;
            areaMax = (schemeBean.getArea() != null && areaMax < schemeBean.getArea()) ? schemeBean.getArea() : areaMax;
            areaMin = (schemeBean.getArea() != null && areaMin > schemeBean.getArea()) ? schemeBean.getArea() : areaMin;
            powerMax = (schemeBean.getPower() != null && powerMax < schemeBean.getPower()) ? schemeBean.getPower() : powerMax;
            powerMin = (schemeBean.getPower() != null && powerMin > schemeBean.getPower()) ? schemeBean.getPower() : powerMin;
            timeMax = (schemeBean.getTime() != null && timeMax < schemeBean.getTime()) ? schemeBean.getTime() : timeMax;
            timeMin = (schemeBean.getTime() != null && timeMin > schemeBean.getTime()) ? schemeBean.getTime() : timeMin;


            // 添加到所有方案的信息中
            packageTypeC.addAll(typeC);
            packageModeC.addAll(modeC);

            schemeBean.setChoose(true);

        }
        schemeList = schemeList.stream().filter(s-> s.isChoose()).collect(Collectors.toList());

        // 所有方案的最大最小信息
        schemePackage.setSchemeList(schemeList);
        schemePackage.setPriceMax(priceMax);
        schemePackage.setPriceMin(priceMin);
        schemePackage.setAreaMax(areaMax);
        schemePackage.setAreaMin(areaMin);
        schemePackage.setPowerMax(powerMax);
        schemePackage.setPowerMin(powerMin);
        schemePackage.setTimeMax(timeMax);
        schemePackage.setTimeMin(timeMin);
        schemePackage.setTypeC(packageTypeC);
        schemePackage.setModeC(packageModeC);

        /**
         * 设计考虑排序
         */
        HashMap<String, Func1<SchemeBean, Double>> func1HashMap = new HashMap<>();
        func1HashMap.put("area",SchemeBean::getArea);
        func1HashMap.put("cost",SchemeBean::getPrice);
        func1HashMap.put("consumption",SchemeBean::getPower);
        Func1<SchemeBean, Double> sortFunc = null;
        String prior = inputParam.getData().get("prior").toString();
        sortFunc = func1HashMap.get(prior);
        if(sortFunc == null){
            schemePackage.getSchemeList().sort(Comparator.comparing(SchemeBean::getPrice).reversed());
            return schemePackage;
        }
        schemePackage.getSchemeList().sort(Comparator.comparing(SchemeBean::getArea));
        return schemePackage;
    }


    // ---------------- 2-1获取电路数据（交互三）- 过滤数据 ----------------
    private List<SchemeBean> filterData(FilterSetData filterSetData, List<SchemeBean> schemeBeanList) {
        List<SchemeBean> resList = new ArrayList<>();

        for (SchemeBean schemeBean : schemeBeanList) {
            if (filterSetData.getArea() != null && filterSetData.getArea().size() == 2) {
                if (!(schemeBean.getArea() >= filterSetData.getArea().get(1) && schemeBean.getArea() <= filterSetData.getArea().get(0))) {
                    continue;
                }
            }

            if (filterSetData.getCost() != null && filterSetData.getCost().size() == 2) {
                if (!(schemeBean.getPrice() >= filterSetData.getCost().get(1) && schemeBean.getPrice() <= filterSetData.getCost().get(0))) {
                    continue;
                }
            }

            if (filterSetData.getPow() != null && filterSetData.getPow().size() == 2) {
                if (!(schemeBean.getPower() >= filterSetData.getPow().get(1) && schemeBean.getPower() <= filterSetData.getPow().get(0))) {
                    continue;
                }
            }

            if (filterSetData.getTime() != null && filterSetData.getTime().size() == 2) {
                if (!(schemeBean.getTime() * 1000 >= filterSetData.getTime().get(1) && schemeBean.getTime() * 1000 <= filterSetData.getTime().get(0))) {
                    continue;
                }
            }

            if (filterSetData.getModeC() != null && filterSetData.getModeC().size() > 0) {
                boolean b = false;
                for (String s : filterSetData.getModeC()) {
                    for (String s2 : schemeBean.getModeC()) {
                        if (s.equals(s2)) {
                            b = true;
                            break;
                        }
                    }
                    if (b) break;
                }
                if (!b) continue;
            }

            if (filterSetData.getTypeC() != null && filterSetData.getTypeC().size() > 2) {
                boolean b = false;
                for (String s : filterSetData.getTypeC()) {
                    for (String s2 : schemeBean.getTypeC()) {
                        if (s.equals(s2)) {
                            b = true;
                            break;
                        }
                    }
                    if (b) break;
                }

                if (!b) continue;
            }

            resList.add(schemeBean);
        }

        return resList;

    }

    // ---------------- 2-2获取电路数据（交互三）- 组装数据 ----------------
    private List<CircuitData> packData(List<SchemeBean> schemeList,String token,String mainProjectId) {
        List<CircuitData> circuitDataList = new ArrayList<>();

        // 如果表格有一个下载失败，后面的都不下载了
        // 这里用数组，是因为如果方法里面会修改这个值，如果不定义数组，修改不会生效

        for (SchemeBean schemeBean : schemeList) {
            if(!Boolean.valueOf(redisService.get(Constant.Kill_Circuit_Generation_Thread+mainProjectId))) {
                return null;
            }
            boolean[] download = {true};
            CircuitData circuitData = assembleCircuitData(0, schemeBean, download,token);
            if (circuitData == null) {
                continue;
            }
            circuitDataList.add(circuitData);

        }
        /**
         * 将pcb匹配成功的放在前面
         */
        if (circuitDataList.size() > 0){
            circuitDataList.sort(Comparator.comparing(CircuitData::getPcbExist).reversed());
        }

        int i = 1;
        for (CircuitData circuitData : circuitDataList){
            circuitData.setName("方案" + i);
            circuitData.setDescription("电路方案" + i);
            i += 1;
        }
        return circuitDataList;
    }

    // ---------------- 2-2-1获取电路数据（交互三）- 组装电路数据 ----------------
    private CircuitData assembleCircuitData(int i, SchemeBean schemeBean, boolean[] download,String token) {
        if (schemeBean == null) {
            return null;
        }

        // 一个完整电路方案数据
        LinkedHashMap<String, Map<String, String>> circuitTemplateNames = new LinkedHashMap<>();
        CircuitData circuitData = new CircuitData();

//        circuitData.setName("方案" + i);
//        circuitData.setDescription("电路方案" + i);
        circuitData.setUuid(UUID.randomUUID().toString());

        // 网络替换
        List<List<PinsBean>> replaceNets = new ArrayList<>();
        // 位号替换
        List<List<List<String>>> replaceDesignators = new ArrayList<>();
        // bom数据
        List<List<CircuitData.BomData>> bomList = new ArrayList<>();
        // 工程文件
        List<String> projectFiles = new ArrayList<>();
        // 缩略图
        List<String> images = new ArrayList<>();
        //处理器型号
        String mModel = "";
        //处理器位号
        String mName = "";

        List<String> netFiles = new ArrayList<>();
        //传感电路型号
        List<String> sense_models = new ArrayList<>();
        // 电路名称集合（处理-采集-电源）
        LinkedHashSet<String> cirNameSet = new LinkedHashSet<>();
        // 位号名称
        Set<String> designatorNames = new HashSet<>();
        //bus
        boolean bus = false;
        //U型号
        //U1处理器  U2存储模块  U3通信模块  U4-U16AD  U17-U32数字传感器
        Map<String, String> uDriveContrastMap = new HashMap<>();
        for (int n = 1; n <= 32; n++) {
            uDriveContrastMap.put("U" + n, null);
        }


        // 一个方案有多个电路类型（控制、传感、电源）
        for (String key : schemeBean.getCircuit().keySet()) {
            if (schemeBean.getCircuit().get(key) == null) {
                continue;
            }

            // 一个电路类型有多个采集类型
            Set<String> keySet = schemeBean.getCircuit().get(key).keySet();
            //统计模拟电路数量
            for (String key2 : keySet) {

                // 一个采集类型
                CircuitGroupBean circuitGroupBean = schemeBean.getCircuit().get(key).get(key2);
                // 获取这个采集类型的电路模板集合
                List<CircuitElementBean> circuitElementBeanList = circuitGroupBean.getCircuitElementList();

                // 一个采集类型有多个电路模板，这里循电路模板
                for (CircuitElementBean circuitElementBean : circuitElementBeanList) {

                    /**
                     * 判断数据总线后缀：-M、-S
                     */
                    if(circuitElementBean.getCircuit().getCircuitTypeId() == CircuitTypeEnum.CONTROLLER.getValue()+1){
                        bus = busMatch(circuitElementBean.getBus());
                    }

                    /**
                     * 统计电路模板的使用情况
                     */
                    countCircuitTemplateNames(key2,circuitElementBean,circuitTemplateNames,cirNameSet);

                    // 一个电路模块数据
                    for (int ic = 0; ic < circuitElementBean.getCount(); ic++) {

                        sense_models.add(circuitElementBean.getSenseModel());

                        // bom表处理
                        Map<String, String> bom2 = analysisBom2(circuitElementBean, download, ic, uDriveContrastMap, bomList);
                        if(key.equals(CircuitTypeEnum.CONTROLLER.getCode())){
                            mName = bom2.get("mName");
                            mModel = bom2.get("mModel");
                        }

                        // 网表（引脚表）处理
                        analysisNet(circuitElementBean,download[0],replaceNets,netFiles);

                        // 位号表处理
                        analysisDesignator(circuitElementBean,download[0],replaceDesignators,designatorNames);

                        // 添加电路文件路径
                        projectFiles.add(circuitElementBean.getCircuit().getProjectPath());

                        // 添加电路缩略图
                        images.add(circuitElementBean.getCircuit().getThumbnailPath());

                        // 方案封面图和图表用处理器的图
                        if (key.equals(CircuitTypeEnum.CONTROLLER.getCode())) {
                            circuitData.setThumb(circuitElementBean.getCircuit().getThumbPath());
                            circuitData.setCharts(circuitElementBean.getCircuit().getChartsPath());
                        }
                    }

                }

            }

        }


        // 驱动数据提取-内部连接
        List<DriveMatchBean> allDriveMatchBean = new ArrayList<>();
        // 内部连接
        List<PinsBean> mcuNet = replaceNets.get(0);
        List<DriveMatchBean> inDriveMatchBean = drivenInsideMatching(mcuNet);
        allDriveMatchBean.addAll(inDriveMatchBean);
        /**
         * 驱动数据提取-外部连接
         * 网表匹配数据记录
         */
        // 外部连接
        List<List<List<String>>> replaceNetsReturn = new ArrayList<>();
        replaceNets.forEach(r->{
            replaceNetsReturn.add(new ArrayList<>());
        });
        List<DriveMatchBean> outDriveMatchBean = drivenOutsideMatching(replaceNets, replaceNetsReturn, sense_models,download);
        allDriveMatchBean.addAll(outDriveMatchBean);
        // 驱动数据组装
        DrivenBean drivenBean = newDriveDataAssemble(allDriveMatchBean,mName, mModel,bus);


        uDriveContrastMap.put("U1",mModel);
        // 驱动对比
        List<CircuitData.UDriveContrast> uDriveContrastList = getUDriveContrast(uDriveContrastMap);

        /**
         * PCB匹配
         */
        ArrayList<String> pcbFileList = new ArrayList<>();
        EsCircuitPcb esCircuitPcb = pcbMatch(cirNameSet);
        if(esCircuitPcb != null){
            projectFiles.add(esCircuitPcb.getUrl());
            images.add(esCircuitPcb.getImage());
            circuitData.setPcbExist(1);
        }

        // 引脚属性为空添加下标
        for (int r=1;r<replaceNetsReturn.size()-1;r++){
            List<PinsBean> collect = replaceNets.get(r).stream().filter(f -> StringUtils.isEmpty(f.getProperty())).collect(Collectors.toList());
            for(PinsBean p : collect){
                List<String> pList = new ArrayList<>();
                pList.add(p.getPin());
                pList.add(p.getPin()+"_"+r);
                replaceNetsReturn.get(r).add(pList);
            }
        }

        if(circuitData.getPcbExist() == 1){
            replaceNetsReturn.add(new ArrayList<>());
            replaceDesignators.add(new ArrayList<>());
            bomList.add(new ArrayList<>());
        }
        circuitData.setReplaceNets(replaceNetsReturn);
        circuitData.setReplaceDesignators(replaceDesignators);
        circuitData.setBom(bomList);
        // 工程文件、图片修改url
        String newToken = "&token="+token.replace("Bearer ","");
        List<String> newProjectFiles = new ArrayList<>();
        List<String> newImages = new ArrayList<>();
        for (String p : projectFiles){
            newProjectFiles.add(circuitFilesIp+p+newToken);
        }
        for (String im : images){
            newImages.add(circuitFilesIp+im+newToken);
        }
        circuitData.setProjectFiles(newProjectFiles);
        circuitData.setImages(newImages);
        // 封面图修改url
        circuitData.setThumb(circuitFilesIp+circuitData.getThumb()+newToken);
        // 效率、物料成本
        CircuitData.ParametersData parametersData = new CircuitData.ParametersData();
        parametersData.setEfficiency("0%");
        parametersData.setMaterialCost(schemeBean.getPrice());
        parametersData.setArea(schemeBean.getArea());
        circuitData.setCircuitTemplateNames(circuitTemplateNames);
        circuitData.setParameters(parametersData);
        circuitData.setuDriveContrastList(uDriveContrastList);
        circuitData.setPCBFiles(pcbFileList);


        List<String> pcbName = new ArrayList<>(cirNameSet);
        pcbName.add(1,pcbName.get(pcbName.size()-1));
        pcbName.remove(pcbName.size()-1);
        drivenBean.getMsg().put("PCB_Name",pcbName.toString().replace(" ",""));
        drivenBean.getMsg().put("netFiles",netFiles);
        drivenBean.getMsg().put("projectFiles",projectFiles);
        drivenBean.getMsg().put("images",images);
        drivenBean.getMsg().put("bomList",bomList);
        drivenBean.getMsg().put("replaceNets",replaceNetsReturn);
        drivenBean.getMsg().put("replaceDesignators",replaceDesignators);
        drivenBean.setCircuitTemplates(circuitTemplateNames);
        circuitData.setDriveData(JSONObject.toJSONString(drivenBean));

        // 返回一个完整方案
        return download[0] ? circuitData : null;
    }

    private Map<String, String> analysisBom2(CircuitElementBean circuitElementBean,
                              boolean[] download,
                              int ic, Map<String, String> uDriveContrastMap,
                              List<List<CircuitData.BomData>> bomList){
        Map<String, String> map = new HashMap<>();
        // 判断Bom表格地址是否为空，不为空的话下载，解析成实体
        String bomPath = circuitElementBean.getCircuit().getBomPath();
        if (!StringUtils.isBlank(bomPath) && download[0]) {
            List<CircuitData.BomData> bomDataList = analysisBom(bomPath);
            if (bomDataList == null) {
                download[0] = false;
            } else {
                Map<String, EsElement> elementMap = null;
                if (circuitElementBean.getElementList() != null && circuitElementBean.getElementList().size() > 0) {
                    elementMap = circuitElementBean.getElementList().get(ic);
                }
                // 替换电路生成规则找到的元器件值
                for (CircuitData.BomData bomData : bomDataList) {

                    if (elementMap != null && elementMap.get(bomData.getDesignator()) != null) {
                        bomData.setValue(elementMap.get(bomData.getDesignator()).getValue());
                    }

                    String designator = bomData.getDesignator();
                    //u型号map   key:u几  value：型号
                    if ("U".equals(designator.toUpperCase().subSequence(0, 1))) {
                        uDriveContrastMap.put(designator, bomData.getComment());
                    }


                    if ("M".equals(designator.subSequence(0, 1)) && mName(designator)){
                        map = new HashMap<>();
                        map.put("mName",designator);
                        map.put("mModel",bomData.getComment());

                    }

                }
                bomList.add(bomDataList);
            }

        }
        return map;
    }

    /**
     *
     * @param circuitElementBean
     * @param download
     * @param replaceDesignators 位号修改列表
     */
    private void analysisDesignator(CircuitElementBean circuitElementBean,
                                    boolean download,
                                    List<List<List<String>>> replaceDesignators,
                                    Set<String> designatorNames){
        // 修改一个电路模板位号
        List<List<String>> rows = new ArrayList<>();
        // 解析电路位号替换表
        if (!StringUtils.isBlank(circuitElementBean.getCircuit().getDesignatorsPath()) && download) {
            List<List<String>> designatorList = analysisDesignators(circuitElementBean.getCircuit().getDesignatorsPath());
            if (designatorList != null) {
                for (int s = 0; s < designatorList.size(); s++) {
                    // 修改一个位号
                    List<String> row = designatorChange(designatorList.get(s).get(1), designatorNames, 0);
                    if(row != null){
                        rows.add(row);
                    }
                }
            }

        }

//        /**
//         * 网表(引脚)属性为空者也需修改
//         */
//        beanIsNull(beans,lists,cirTypeIndex);

        replaceDesignators.add(rows);
    }

    public List<String> designatorChange(String designatorName,Set<String> designatorNames,int index){
        String newDesignatorName = index != 0 ? (designatorName +"_"+ index) : designatorName;
        if(designatorNames.contains(newDesignatorName)){
            index++;
            return designatorChange(designatorName,designatorNames,index);
        }
        designatorNames.add(newDesignatorName);
        if(index != 0){
            List<String> list = new ArrayList<>();
            list.add(designatorName);
            list.add(newDesignatorName);
            return list;
        }
        return null;
    }

    /**
     *
     * @param beans 网表数据
     * @param lists 网表修改的数据
     * @param cirTypeIndex 同一电路类型（处理、电源、传感）下的第几个网表
     */
    private void beanIsNull(List<PinsBean> beans, List<List<String>> lists, int cirTypeIndex){
        if(cirTypeIndex == 0) {
            return;
        }
        // 网表(引脚)属性为空者也需修改
        List<PinsBean> newBeans =beans.stream().filter(b->StringUtils.isEmpty(b.getProperty())).collect(Collectors.toList());
        if(newBeans.size() > 0){
            for(PinsBean p : newBeans){
                List<String> netReplace = new ArrayList<>();
                netReplace.add(p.getPin());
                netReplace.add(p.getPin()+"_"+cirTypeIndex);
                lists.add(netReplace);
            }
        }
    }

    /**
     *
     * @param circuitElementBean
     * @param netFiles 网表路径列表
     * @param replaceNets 网表解析数据列表
     */
    private void analysisNet(CircuitElementBean circuitElementBean,
                             boolean download,
                             List<List<PinsBean>> replaceNets,
                             List<String> netFiles){
        // 解析电路网络替换表
        String netPath = circuitElementBean.getCircuit().getNetPath();
        netFiles.add(netPath);
        List<PinsBean> analysisNetList = new ArrayList<>();
        if (!StringUtils.isBlank(netPath) && download) {
            analysisNetList = analysisNet(netPath);
        }
        replaceNets.add(analysisNetList);
    }

    /**
     *
     * @param key2
     * @param circuitElementBean
     * @param circuitTemplateNames
     */
    private void countCircuitTemplateNames(String key2,
                                           CircuitElementBean circuitElementBean,
                                           Map<String, Map<String, String>> circuitTemplateNames,
                                           LinkedHashSet<String> cirNameSet){
        String name = circuitElementBean.getCircuit().getName();
        cirNameSet.add(name);
        name = name + "(个数:" + circuitElementBean.getCount() + "、" + "芯片所属："+key2+")";
        if (!circuitTemplateNames.containsKey(name)) {
            Long id = circuitElementBean.getCircuit().getId();
            EsCircuitCodeData esCircuitCodeData = new EsCircuitCodeData();
            esCircuitCodeData.setCircuitId(id);
            List<EsCircuitCodeData> esCircuitCodeDataList = esCircuitCodeDataService.selectEsCircuitCodeDataList(esCircuitCodeData);
            Map<String, String> map = new HashMap<>();
            esCircuitCodeDataList.forEach(e -> {
                String keyName = e.getCircuitCodeDataTemplate().getName();
                String value = e.getValue();
                map.put(keyName, value);
            });
            circuitTemplateNames.put(name, map);
        }
    }

    // ---------------- 2-3获取电路数据（交互三）- 分页电路数据 ----------------
    private List<CircuitData> pagingCircuit(int page, int pageSize, List<CircuitData> circuitDataList) {

        List<CircuitData> listSort = new ArrayList<>();
        int size = circuitDataList.size();
        int pageStart = page == 1 ? 0 : (page - 1) * pageSize;//截取的开始位置
        int pageEnd = size < page * pageSize ? size : page * pageSize;//截取的结束位置
        if (size > pageStart) {
            listSort = circuitDataList.subList(pageStart, pageEnd);
        }
        return listSort;


    }

    // ---------------- 2-4获取电路数据（交互三）- 组装返回过滤条件参数 ----------------
    private void packFilterRangeData(FilterRangeData filterRangeData, SchemePackageBean schemePackage) {
        FilterRangeData.Value value = new FilterRangeData.Value();
        FilterRangeData.Label label = new FilterRangeData.Label();

        List<FilterRangeData.Data> area = new ArrayList<>();
        area.add(new FilterRangeData.Data((int) Math.ceil(schemePackage.getAreaMax()), "mm²"));
        area.add(new FilterRangeData.Data((int) Math.floor(schemePackage.getAreaMin()), "mm²"));
        value.setArea(area);

        List<FilterRangeData.Data> pow = new ArrayList<>();
        pow.add(new FilterRangeData.Data((int) Math.ceil(schemePackage.getPowerMax()), "毫瓦"));
        pow.add(new FilterRangeData.Data((int) Math.floor(schemePackage.getPowerMin()), "毫瓦"));
        value.setPow(pow);

        List<FilterRangeData.Data> cost = new ArrayList<>();
        cost.add(new FilterRangeData.Data((int) Math.ceil(schemePackage.getPriceMax()), "元"));
        cost.add(new FilterRangeData.Data((int) Math.floor(schemePackage.getPriceMin()), "元"));
        value.setCost(cost);

        // 秒、分钟、时、天转换
        List<FilterRangeData.Data> time = new ArrayList<>();
        String timeUnit = "秒";
        Double timeMin = schemePackage.getTimeMin();
        Double timeMax = schemePackage.getTimeMax();
        if (timeMin > (60 * 60 * 24)) {
            timeMax = timeMax / (60 * 60 * 24);
            timeMin = timeMin / (60 * 60 * 24);
            timeUnit = "天";
        } else if (timeMin > 60 * 60) {
            timeMax = timeMax / (60 * 60);
            timeMin = timeMin / (60 * 60);
            timeUnit = "小时";
        } else if (timeMin > 60) {
            timeMax = timeMax / 60;
            timeMin = timeMin / 60;
            timeUnit = "分钟";
        }
        time.add(new FilterRangeData.Data((int) Math.ceil(timeMax), timeUnit));
        time.add(new FilterRangeData.Data((int) Math.floor(timeMin), timeUnit));
//        value.setTime(time);

        if (schemePackage.getTypeC() != null) {
            List<String> typeC = new ArrayList<>(schemePackage.getTypeC());
            value.setTypeC(typeC);
        }

        if (schemePackage.getModeC() != null) {
            List<String> modeC = new ArrayList<>(schemePackage.getModeC());
            value.setModeC(modeC);
        }

        filterRangeData.setValue(value);
        filterRangeData.setLabel(label);
    }

    private List<CircuitData.UDriveContrast> Supported_1(String[] uDriveList){
        List<CircuitData.UDriveContrast> uDriveContrastList = new ArrayList<>();
        for(String u : uDriveList){
            CircuitData.UDriveContrast contrast = new CircuitData.UDriveContrast();
            contrast.setComment(u.substring(0,u.indexOf("_")));
            contrast.setIsSupported(-1);
            uDriveContrastList.add(contrast);
        }
        return uDriveContrastList;    }

    /**
     * 判断是否有驱动支持
     * @param map
     * @return
     */
    private List<CircuitData.UDriveContrast> getUDriveContrast(Map<String, String> map) {
        List<CircuitData.UDriveContrast> uDriveContrastList = new ArrayList<>();
        UDriveContrastBean.ChipDriverMatrix matrixByMasterChipId = null;
        List<Integer> supportSlaveChipId = null;
        String[] uDriveList = {"存储模块_2", "通信模块_3", "AD模块_4-16", "数字传感器_17-32"};

        //获取驱动bom表
//        UDriveContrastBean driveContrastExel = getDriverData();
        UDriveContrastBean driveContrastExel = null;
        if (driveContrastExel == null){
            return Supported_1(uDriveList);
        }

        //判断U1是否为空
        String u1 = map.get("U1");
        if (u1 == null){
            return Supported_1(uDriveList);
        }

        //判断仓库是否拥有u1
        UDriveContrastBean.ChipInfo U1ChipInfo = driveContrastExel.getData().getChipInfoByModel(u1);
        if (U1ChipInfo == null){
            return Supported_1(uDriveList);
        }

        map.remove("U1");
        //获取主控芯片的整体信息
        matrixByMasterChipId = driveContrastExel.getData().getchipDriverMatrixByMasterChipId(U1ChipInfo.getChipId());
        //获取主控芯片支持的子芯片列表
        supportSlaveChipId = matrixByMasterChipId.getSupportSlaveChipId();

        for(String ud : uDriveList){
            CircuitData.UDriveContrast uDrive = new CircuitData.UDriveContrast();
            uDrive.setComment(ud.substring(0,ud.indexOf("_")));
            uDrive.setIsSupported(0);
            uDriveMatchAll(ud.substring(ud.indexOf("_")+1),uDrive,map,driveContrastExel,supportSlaveChipId);
            uDriveContrastList.add(uDrive);
        }

        return uDriveContrastList;
    }
    private void uDriveMatchAll(String ud,
                                CircuitData.UDriveContrast uDrive,
                                Map<String, String> map,
                                UDriveContrastBean driveContrastExel,
                                List<Integer> supportSlaveChipId) {
        int start = 0;
        int end = 0;
        if(ud.indexOf("-") == -1){
            start = end = Integer.valueOf(ud);
        }else{
            int[] ints = Arrays.stream(ud.split("-")).mapToInt(Integer::parseInt).toArray();
            start = ints[0];
            end = ints[1];
        }
        for (int uInt = start; uInt <= end; uInt++) {
            //判断是否存在通信模块
            if (map.get("U" + uInt) == null) {
                continue;
            }
            //判断仓库是否拥有此通信模块
            UDriveContrastBean.ChipInfo uChipInfo = driveContrastExel.getData().getChipInfoByModel("U" + uInt);
            if (uChipInfo != null && supportSlaveChipId.contains(uChipInfo.getChipId())) {
                uDrive.setIsSupported(1);
            }else {
                /**
                 * 存在不支持即不支持
                 */
                uDrive.setIsSupported(-1);
            }

        }
    }

    // 获取驱动程序的芯片支持数据
    private UDriveContrastBean getDriverData() {
        OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(Constants.getDriverDataUrl)
                .addHeader("contentType", "application/json")
                .addHeader("authorization", tokenService.createJwt("2567a5ec9705eb7ac2c984033e06189d"));
        String data = okHttpUtils.postBody(true).sync();
        if (StringUtils.isEmpty(data) || data.contains("失败")) {
            return null;
        }

        UDriveContrastBean uDriveContrastBean = JSON.parseObject(data, UDriveContrastBean.class);
        return uDriveContrastBean;

    }

    private static String nodeSetModel(String senseModel,boolean bus){
        if(!StringUtils.isEmpty(senseModel) && !senseModel.contains("DRIVER")){
            return senseModel;
        }
        if (bus){
            return "VirtualMasterChip";
        }
        return "VirtualSlaveChip";
    }

    private static boolean mName(String name){
        String substring = name.substring(1);
        return NumberUtils.isParsable(substring);
    }

    private static DrivenBean newDriveDataAssemble(List<DriveMatchBean> allDriveMatchBean,
                                                   String mName,
                                                   String mModel,
                                                   boolean bus){
        allDriveMatchBean = allDriveMatchBean.stream()
                .filter(d -> d.getSenseType().contains("GPIO") || d.getSenseType().contains("ADC") ? false : true)
                .collect(Collectors.toList());
        String preChipCode = "MV";
        int endChipCode = 0;

        DrivenBean drivenBean = new DrivenBean();
        List<DrivenBean.Node> nodes = new ArrayList<>();
        List<DrivenBean.Edge> edges = new ArrayList<>();

        //添加M1的node
        DrivenBean.Node nodeM1 = new DrivenBean.Node();
        nodeM1.setChipCode(mName);
        String m1Model = nodeSetModel(mModel, bus);
        nodeM1.setModel(m1Model);
        nodes.add(nodeM1);

        for(DriveMatchBean d : allDriveMatchBean){
            endChipCode++;
            //设置node
            DrivenBean.Node node = new DrivenBean.Node();
            node.setChipCode(preChipCode+endChipCode);
            String s = nodeSetModel(d.getSenseModel(), bus);
            node.setModel(s);
            nodes.add(node);

            //设置edge
            String mPropertySplit = mcuPropertySplit(d.getMcuProperty(), d.getSenseType(),"");
            int indexOf = mPropertySplit.indexOf("_");
            if(indexOf == -1){
                indexOf = mPropertySplit.length();
            }
            String substring = mPropertySplit.substring(0, indexOf);

            List<DrivenBean.Pin> pinList = new ArrayList<>();
            Set<String> keySet = d.getGroupData().keySet();
            for(String key:keySet){
                String value = d.getGroupData().get(key);
                DrivenBean.Pin pin = new DrivenBean.Pin();
                pin.setMasterChipResourceName(key);
                String propertySplit = mcuPropertySplit(value, d.getSenseType(),substring);
                pin.setSlaveChipInterfaceName(propertySplit);
                pinList.add(pin);
            }


            DrivenBean.PeripheralData peripheralData = new DrivenBean.PeripheralData();
            peripheralData.setMasterChipPeripheralName(substring);
            peripheralData.setSlaveChipPeripheralTypeName(d.getSenseType());
            DrivenBean.ConfigData configData = new DrivenBean.ConfigData();
            configData.setPeripheralData(peripheralData);
            configData.setPinList(pinList);
            DrivenBean.Data data = new DrivenBean.Data();
            data.setConfigData(configData);

            DrivenBean.Edge edge = new DrivenBean.Edge();
            edge.setSourceChipCode(mName);
            edge.setTargetChipCode(preChipCode+endChipCode);
            edge.setData(data);
            edges.add(edge);

        }
        drivenBean.setNodes(nodes);
        drivenBean.setEdges(edges);
        return drivenBean;
    }

    /**
     * 处理器属性匹配切割
     * @param str
     * @param type
     * @return
     */
    private static String mcuPropertySplit(String str,String type,String substring ){
        if(substring.contains("GPIO")){
            return "GPIO";
        }
        if(!StringUtils.isEmpty(substring)){
            substring = substring + "_";
        }
        if(type.indexOf("_") != -1){
            type = type.substring(0,type.indexOf("_"));
        }
        String[] split = str.split("\\\\");
        for(String s:split){
            if(s.contains(type)){
                String replace = s.replace(substring, "");
                return replace;
            }
        }
        String replace = str.replace(substring, "");
        return replace;
    }

    /**
     * 引脚驱动内部连接数据提取
     * @param mcuNet
     * @return
     */
    private static List<DriveMatchBean> drivenInsideMatching(List<PinsBean> mcuNet){
        //1、获取已进行内部连接的引脚（已占用）
        List<PinsBean> insideList = mcuNet.stream().filter(m -> m.isOccupied()).collect(Collectors.toList());
        //2、获取型号集合，后面按照型号进行分组
        Set<String> modelSet = insideList.stream().map(PinsBean::getModel).collect(Collectors.toSet());
        //3、进行分组
        HashMap<String, List<PinsBean>> map = new HashMap<>();
        for(String model : modelSet){
            List<PinsBean> pinsByModel = insideList.stream().
                    filter(n -> n.getModel().contains(model)).collect(Collectors.toList());
            map.put(model,pinsByModel);
        }
        //4、封装数据
        List<DriveMatchBean> driveMatchBeanList = new ArrayList<>();
        for(String model:map.keySet()){
            List<PinsBean> pinsBeanList = map.get(model);
            Map<String, String> groupMap = pinsBeanList.stream().collect(Collectors.toMap(PinsBean::getPin, PinsBean::getProperty));
            PinsBean p = pinsBeanList.get(0);
            DriveMatchBean driveMatchBean = new DriveMatchBean();
            driveMatchBean.setSenseModel(p.getModel());
            driveMatchBean.setSenseType(p.getType());
            driveMatchBean.setMcuProperty(p.getProperty());
            driveMatchBean.setGroupData(groupMap);
            driveMatchBeanList.add(driveMatchBean);
        }
        return driveMatchBeanList;
    }

    /**
     * 引脚驱动外部连接数据提取、引脚修改数据提取
     *
     * @param replaceNets
     * @param replaceNetsReturn 引脚修改数据集合
     * @param sense_models      处理器的型号数据集
     * @param download
     * @return
     */
    private static List<DriveMatchBean> drivenOutsideMatching(List<List<PinsBean>>replaceNets,
                                                              List<List<List<String>>> replaceNetsReturn,
                                                              List<String> sense_models, boolean[] download){
        //进行网表匹配(返回结果为网表替换数据)，匹配同时提取数据
        String jsonString = JSONObject.toJSONString(replaceNets);
//        List<List<PinsBean>> newReplaceNets = (List<List<PinsBean>>)JSONObject.parseObject(jsonString);
        List<List<PinsBean>> newReplaceNets = JSON.parseObject(jsonString, new TypeReference<List<List<PinsBean>>>(){});
        return netsMatching(newReplaceNets, replaceNetsReturn, sense_models,download);
    }

    /**
     * 对网表数据进行初步处理,并进行匹配
     */
    private static List<DriveMatchBean> netsMatching(List<List<PinsBean>> replaceNets,
                                                     List<List<List<String>>> nets,
                                                     List<String> senseModels, boolean[] download){


        /**
         * 移除电源网表、已占用的引脚、没有属性的引脚
         */

        List<List<PinsBean>> lists = removePinsBean(replaceNets);

        /**
         * 开始匹配
         */

        return startMatching(lists,nets,senseModels,download);

    }

    /**
     * 开始匹配-gpio匹配
     */
    private static void gpioMatch(int i,
                                  List<PinsBean> mcuList,
                                  PinsBean s,
                                  List<List<List<String>>> nets,
                                  Map<String,String> map, boolean[] download){
        for(PinsBean m:mcuList){
            if(!m.isOccupied() && m.getProperty().equals("GPIO")){
                setMassage(i,m,s,map,nets);
                m.setOccupied(true);
                s.setOccupied(true);
                break;
            }
        }
        if(!s.isOccupied()){
            for(PinsBean m:mcuList){
                if(!m.isOccupied() && m.getProperty().contains("GPIO")){
                    setMassage(i,m,s,map,nets);
                    m.setOccupied(true);
                    s.setOccupied(true);
                    break;
                }
            }
            if(!s.isOccupied()){
                download[0] = false;
            }
        }
    }

    /**
     * 开始匹配-类型匹配
     */
    private static Map<String, String> typeMatch(int i,
                                                 List<PinsBean> mcuList,
                                                 List<PinsBean> senseList,
                                                 List<List<List<String>>> nets,
                                                 DriveMatchBean newDriveMatchBean, boolean[] download) {
        Map<String, String> map = new HashMap<>();
        String mcuProperty = null;
        for (PinsBean s : senseList) {
            if (StringUtils.isEmpty(s.getType())) {
                //属性匹配
                mcuProperty = proMatch(i, mcuList, s, map, nets,download);
            }else  {
                //类型匹配
                mcuProperty = proMatch2(i, mcuList, s, map, nets,download);
            }
        }
        newDriveMatchBean.setMcuProperty(mcuProperty);
        return map;
    }

    private static String proMatch2(int i,
                                    List<PinsBean> mcuList,
                                    PinsBean s,
                                    Map<String,String> map,
                                    List<List<List<String>>> nets, boolean[] download){
        for(PinsBean m:mcuList){
            if(!m.isOccupied() && m.getType().equals(s.getType()) && m.getProperty().contains(s.getProperty())){
                setMassage(i,m,s,map,nets);
                //判断引脚是否可复用
                boolean b = isMultiplexing(s.getProperty());
                m.setOccupied(b);
                s.setOccupied(true);
                return m.getProperty();
            }
        }
        if(!s.isOccupied()){
            return proMatch(i, mcuList, s, map, nets,download);
        }
        return null;
    }

    private static String proMatch(int i,
                                   List<PinsBean> mcuList,
                                   PinsBean s,
                                   Map<String,String> map,
                                   List<List<List<String>>> nets, boolean[] download){

        for(PinsBean m:mcuList){
            if(s.getProperty().contains("GPIO")){
                break;
            }
            if(!m.isOccupied() && m.getProperty().contains(s.getProperty())){
                setMassage(i,m,s,map,nets);
                //判断引脚是否可复用
                boolean b = isMultiplexing(s.getProperty());
                m.setOccupied(b);
                s.setOccupied(true);
                return m.getProperty();
            }
        }
        //匹配失败则插入到GPIO引脚
        if(!s.isOccupied()){
            gpioMatch(i, mcuList, s, nets,map,download);
            return "GPIO";
        }
        return null;
    }

    private static boolean isMultiplexing(String property){
        if(property.contains("_SCK")
                || property.contains("_MISO")
                || property.contains("_MOSI")){
            return false;
        }
        return true;
    }

    private static void setMassage(int i,
                                   PinsBean m,
                                   PinsBean s,
                                   Map<String,String> map,
                                   List<List<List<String>>> nets){
        String pinProperty = m.getPin()+"-"+s.getProperty();
        //设置处理器引脚替换信息
        List<String> m_net = new ArrayList<>();
        m_net.add(m.getPin());
        m_net.add(pinProperty);
        nets.get(0).add(m_net);
        //设置传感器引脚替换信息
        List<String> s_net = new ArrayList<>();
        s_net.add(s.getPin());
        s_net.add(pinProperty);
        nets.get(i+1).add(s_net);
        if(map != null) map.put(m.getPin(),m.getProperty());
    }


    /**
     * 开始匹配
     */
    private static List<DriveMatchBean> startMatching(List<List<PinsBean>> lists,
                                                      List<List<List<String>>> nets,
                                                      List<String> senseModels, boolean[] download){
        List<PinsBean> mcuList = lists.remove(0);
        List<List<PinsBean>> senseList = lists;

        /**
         * 1、循环传感电路进行匹配
         * 2、进行提取外部连接数据时，一个传感电路为一组。
         */
        List<DriveMatchBean> driveMatchBeanList = new ArrayList<>();
        for(int i=0;i<senseList.size();i++){

            String senseModel = senseModels.get(i);
            DriveMatchBean newDriveMatchBean= new DriveMatchBean();

            List<PinsBean> pinsBeanList = senseList.get(i);
            Map<String, String> groupData = typeMatch(i, mcuList, pinsBeanList, nets,newDriveMatchBean,download);

            PinsBean pinsBean = pinsBeanList.get(0);
            String senseType = StringUtils.isEmpty(pinsBean.getType()) ? pinsBean.getProperty() : pinsBean.getType();
            newDriveMatchBean.setSenseType(senseType);
            newDriveMatchBean.setSenseModel(senseModel);
            newDriveMatchBean.setGroupData(groupData);
            driveMatchBeanList.add(newDriveMatchBean);

        }
        return driveMatchBeanList;
    }

    private static boolean isExtractData(String replace){
        boolean b = replace.equals("GPIO");
        boolean d = replace.equals("ADC");
        return b || d;
    }


    /**
     * 对网表数据进行初步处理-移除电源网表、移除已占用的引脚、没有属性的引脚
     */
    private static List<List<PinsBean>> removePinsBean(List<List<PinsBean>> replaceNets){
        List<List<PinsBean>> newReplaceNets = new ArrayList<>();

        /**
         * 移除电源网表
         */
        int size = replaceNets.size();
        replaceNets.remove(size-1);


        /**
         * 移除已占用的引脚、没有属性的引脚
         */
        for(List<PinsBean> pinsBeanList : replaceNets){
            pinsBeanList = pinsBeanList.stream().filter(p->{
                if(!p.isOccupied() && !StringUtil.isBlank(p.getProperty()))
                    return true;
                return false;
            }).collect(Collectors.toList());
            newReplaceNets.add(pinsBeanList);
        }


        return newReplaceNets;
    }

    private boolean netsMatchReplace(int type ,int i, List<List<PinsBean>> nets, List<PinsBean> controllerNet, PinsBean sensorRow, String sensorPin, String sensorProperty) {
        for (PinsBean controllerRow : controllerNet) { // 循环处理器电路网表
            // 如果单行网表没有数据，跳过
            if (controllerRow == null
                    || StringUtil.isBlank(controllerRow.getPin())
                    || StringUtil.isBlank(controllerRow.getProperty())) {
                continue;
            }

            // 引脚被占用，跳过
            if (controllerRow.isOccupied()) {
                continue;
            }

            // 处理器引脚
            String controllerPin = controllerRow.getPin();
            // 处理器属性
            String controllerProperty = controllerRow.getProperty();

            if (type == 1){
                // 如果处理属性和传感器属性匹配
                if (controllerProperty.contains(sensorProperty)) {
                    // 如果引脚只能占用一次的标识上
                    if (sensorProperty.equals("SPI_NSS")
                            || sensorProperty.equals("I2C1_CSL")
                            || sensorProperty.equals("I2C1_SDA")
                            || sensorProperty.equals("I2C1_SMBA")) {
                        controllerRow.setOccupied(true);

                    }

                    // 在原数据上标识已经处理过，下面再对没有处理过的进行二次处理
                    netsMatchReplaceHandle(i, nets, sensorRow, sensorPin, sensorProperty, controllerPin);

                    return true;
                }
            }else {
                // 如果处理属性和传感器属性匹配
                if ("GPIO".equals(controllerProperty)) {

                    // 处理器标识被用了
                    controllerRow.setOccupied(true);

                    netsMatchReplaceHandle(i, nets, sensorRow, sensorPin, sensorProperty, controllerPin);

                    return true;

                }
            }

        }

        return false;
    }

    private void netsMatchReplaceHandle(int i, List<List<PinsBean>> nets, PinsBean sensorRow, String sensorPin, String sensorProperty, String controllerPin){
        // 在原数据上标识已经处理过
        sensorRow.setOccupied(true);

        // 添加新的单行网表数据到新的传感电路nets
        PinsBean newSensorRow = new PinsBean();
        newSensorRow.setPin(sensorPin);
        newSensorRow.setProperty(sensorProperty + "-" + controllerPin);
        nets.get(i).add(newSensorRow);

        // 添加新的单行网表数据到新的处理器电路nets
        PinsBean newControllerNet = new PinsBean();
        newControllerNet.setPin(controllerPin);
        newControllerNet.setProperty(sensorProperty + "-" + controllerPin);
        nets.get(0).add(newControllerNet);
    }


    // --------------------------------------通用方法---------------------------------------------------

    // 解析bom表格
    public List<CircuitData.BomData> analysisBom(String bomPath) {


        InputStreamWorkbookHelper inputStreamWorkbookHelper = new InputStreamWorkbookHelper(remoteFileService) {
            @Override
            public List<CircuitData.BomData> run(Workbook workbook) {
                List<CircuitData.BomData> bomDataList = new ArrayList<>();
                if (workbook == null) {
                    return null;
                }

                // 解析每个sheet
                for (int numsheet = 0; numsheet < workbook.getNumberOfSheets(); numsheet++) {
                    Sheet hssfSheet = workbook.getSheetAt(numsheet);
                    if (hssfSheet == null) continue;

                    Map<String, Integer> headMap = new HashMap<>();
                    // 取出表头
                    Row headRow = hssfSheet.getRow(0);
                    // 取出每个单元格数据
                    for (int i = 0; i < headRow.getLastCellNum(); i++) {
                        Cell cell = headRow.getCell(i);
                        if (cell == null) continue;
                        cell.setCellType(CellType.STRING);
                        headMap.put(StringUtils.trim(cell.getStringCellValue()), i);
                    }

                    // 取出每一行数据
                    bb:
                    for (int rowNum = 1; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
                        Row xssfRow = hssfSheet.getRow(rowNum);
                        if (xssfRow == null)  continue bb;

                        CircuitData.BomData bomData = new CircuitData.BomData();
                        // 取出每个单元格数据
                        for (int i = 0; i < xssfRow.getLastCellNum(); i++) {
                            Cell cell = xssfRow.getCell(i);
                            if (cell == null)  continue;

                            cell.setCellType(CellType.STRING);
                            if (i == headMap.get("Comment")) {
                                // 元器件唯一编码，等于专家系统的元器件库编码
                                bomData.setComment(StringUtils.trim(cell.getStringCellValue()));
                            } else if (i == headMap.get("Designator")) {
                                // 位号，一行数据会有多个位号，下面要把每一个位号分解出来独立一行
                                bomData.setDesignator(StringUtils.trim(cell.getStringCellValue()));
                            } else if (i == headMap.get("Footprint")) {
                                // 封装名
                                bomData.setFootprint(StringUtils.trim(cell.getStringCellValue()));
                            } else if (i == headMap.get("Value")) {
                                // 值
                                bomData.setValue(StringUtils.trim(cell.getStringCellValue()));
                            } else if (i == headMap.get("Device")) {
                                // 器件标题
                                bomData.setDevice(StringUtils.trim(cell.getStringCellValue()));
                            } else if (i == headMap.get("Name")) {
                                // 元件名
                                bomData.setName(StringUtils.trim(cell.getStringCellValue()));
                            }
                        }

                        if (!StringUtils.isBlank(bomData.getDesignator())) {
                            // 一行数据会有多个位号，下面要把每一个位号分解出来独立一行
                            String[] designatorArr = bomData.getDesignator().split(",");
                            if (designatorArr.length > 1) {
                                for (String designator : designatorArr) {
                                    if (StringUtils.isBlank(designator)) continue;
                                    CircuitData.BomData newBomData = new CircuitData.BomData();
                                    newBomData.setDesignator(designator);
                                    newBomData.setFootprint(bomData.getFootprint());
                                    newBomData.setValue(bomData.getValue());
                                    newBomData.setDevice(bomData.getDevice());
                                    newBomData.setName(bomData.getName());
                                    bomDataList.add(newBomData);
                                }
                            } else {
                                bomDataList.add(bomData);
                            }
                        }
                    }
                }
                return bomDataList;
            }
        };
        List<CircuitData.BomData> lists = (List<CircuitData.BomData>) inputStreamWorkbookHelper.invoke(bomPath);
        return lists;
    }


    // 解析位号替换表格
    public List<List<String>> analysisDesignators(String designatorExcelUrl) {

        InputStreamWorkbookHelper<List<List<String>>> inputStreamWorkbookHelper = new InputStreamWorkbookHelper(remoteFileService) {
            @Override
            public List<List<String>> run(Workbook workbook) {
                List<List<String>> arrayList = new ArrayList<>();

                // 解析每个sheet
                Sheet hssfSheet = workbook.getSheetAt(0);
                if (hssfSheet == null) {
                    return null;
                }

                for (int rowNum = 1; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
                    Row xssfRow = hssfSheet.getRow(rowNum);
                    if (xssfRow == null) {
                        continue;
                    }
                    List<String> stringList = new ArrayList<>();
                    // 取出每个单元格数据
                    for (int i = 0; i < xssfRow.getLastCellNum(); i++) {
                        Cell cell = xssfRow.getCell(i);
                        if (cell == null) {
                            continue;
                        }
                        String cellValue;
                        if (cell.getCellType() == CellType.NUMERIC) {
                            cellValue = String.valueOf(cell.getNumericCellValue());
                        } else {
                            cellValue = cell.getStringCellValue();
                        }
                        stringList.add(StringUtils.trim(cellValue));
                    }
                    arrayList.add(stringList);
                }
                return arrayList;
            }
        };
        List<List<String>> lists = inputStreamWorkbookHelper.invoke(designatorExcelUrl);
        return lists;
    }

    // 解析网络替换表格
    public List<PinsBean> analysisNet(String netsExcelUrl) {

        InputStreamWorkbookHelper<List<PinsBean>> inputStreamWorkbookHelper = new InputStreamWorkbookHelper(remoteFileService) {
            @Override
            public List<PinsBean> run(Workbook workbook) {
                if (workbook == null) {
                    return new ArrayList<>();
                }

                Sheet hssfSheet = workbook.getSheetAt(0);
                List<PinsBean> pinsBeanList = new ArrayList<>();

                // 取出每一行数据
                for (int rowNum = 1; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
                    Row xssfRow = hssfSheet.getRow(rowNum);
                    if (xssfRow == null) {
                        continue;
                    }

                    PinsBean pinsBean = new PinsBean();
                    // 取出每个单元格数据，固定9列
                    for (int i = 0; i < 9; i++) {
                        Cell cell = xssfRow.getCell(i);
                        String data = null;
                        if (cell != null) {
                            if (cell.getCellType() == CellType.NUMERIC) {
                                data = String.valueOf(cell.getNumericCellValue());
                            } else {
                                data = cell.getStringCellValue();
                            }
                        }
                        if(StringUtils.isEmpty(data)) continue;
                        switch (i) {
                            case 0:
                                pinsBean.setPin(data);
                                break;
                            case 1:
                                pinsBean.setProperty(data);
                                break;
                            case 2:
                                pinsBean.setOccupied(StringUtils.hasText(data));
                                break;
                            case 3:
                            case 5:
                            case 7:
                                pinsBean.setType(data);
                                break;
                            case 4:
                            case 6:
                            case 8:
                                pinsBean.setModel(data);
                                break;
                        }
                    }
                    pinsBeanList.add(pinsBean);
                }

                return pinsBeanList;
            }
        };
        List<PinsBean> invoke = inputStreamWorkbookHelper.invoke(netsExcelUrl);
        return invoke;
    }

    /**
     * pcb匹配
     */
    public EsCircuitPcb pcbMatch(LinkedHashSet<String> cirNameSet){
        List<String> pcbName = new ArrayList<>(cirNameSet);
        String conName = pcbName.get(0);
        String powName = pcbName.get(pcbName.size()-1);
        List<EsCircuitPcb> esCircuitPcb = esCircuitPcbService.selectEsCircuitPcbByName2(conName, powName);
        if(esCircuitPcb == null || esCircuitPcb.size() == 0){
            return null;
        }

        bb:
        for (EsCircuitPcb e : esCircuitPcb){
            String senNames = e.getSenNames();
            for(int i=1;i<pcbName.size()-1;i++){
                if(!senNames.contains(pcbName.get(i))){
                    continue bb;
                }
            }
            return e;
        }
        return null;
    }

    private static boolean busMatch(String bus){
        return bus.contains("-M");
    }
}
